#include "dev_reader_uhf.h"
#include "mainwindow.h"

using namespace RFIDLIB;
using namespace std;

CAEDevice_UHF::CAEDevice_UHF(InvenParams*& invenParams)
{
    this->invenParams = invenParams;
    RDType_ID = RDTYPE_UHF;
}
CAEDevice_UHF::~CAEDevice_UHF()
{
    if(invenParams != NULL)
        invenParams = NULL;
    Close();
}

void CAEDevice_UHF::AddNewISO18000P6CTag(UINT32& AIPType, UINT32& tagType, UINT32& antID,
                                            UINT32& metaFlags, BYTE tagData[], UINT32& datlen, string& writeOper, string& lockOper)
        {
            UINT16 epcBitsLen = 0;
            UINT32 idx = 0;
            BYTE epc[MainWindow::UHF_TAG_MAX_WORD_NUMBER*2];
            QString s_epc;
            BYTE readData[MainWindow::UHF_TAG_MAX_WORD_NUMBER*2];
            QString s_rdata;

            UINT32 i;
            UINT32 antId;
            UINT32 timestamp;
            UINT32 frequency;
            BYTE rssi;
            BYTE readCnt;

            timestamp = 0;
            frequency = 0;
            rssi = 0;
            readCnt = 0;
            if (metaFlags == 0) metaFlags |= ISO18000p6C_META_BIT_MASK_EPC;
            if ((metaFlags & ISO18000p6C_META_BIT_MASK_EPC) > 0)
            {
                if (datlen < 2)
                {
                    //error data size
                    return;
                }

                epcBitsLen = (UINT16)(tagData[idx] | (tagData[idx+1] << 8));
                idx += 2;
                UINT32 epcBytes = ((epcBitsLen + 7) / 8);
                if ((datlen - idx) < epcBytes)
                {
                    // error data size
                    return;
                }
                memcpy(epc,tagData+idx,epcBytes);
                CHAR c_epc[epcBytes*2+1];
                memset(c_epc,0,sizeof(c_epc));
                BytesToHexStr(epc,epcBytes,c_epc);
                s_epc = QString(c_epc);

                idx += epcBytes;
            }
            if ((metaFlags & ISO18000P6C_META_BIT_MASK_TIMESTAMP) > 0)
            {
                if ((datlen - idx) < 4)
                {
                    //error data size
                    return;
                }
                timestamp = (UINT32)(tagData[idx] | (tagData[idx + 1] << 8 & 0xff00) | (tagData[idx + 2] << 16 & 0xff0000) | (tagData[idx + 3] << 24 & 0xff000000));
                idx += 4;
            }
            if ((metaFlags & ISO18000P6C_META_BIT_MASK_FREQUENCY) > 0)
            {
                if ((datlen - idx) < 4)
                {
                    //error data size
                    return;
                }
                frequency = (UINT32)(tagData[idx] | (tagData[idx + 1] << 8 & 0xff00) | (tagData[idx + 2] << 16 & 0xff0000) | (tagData[idx + 3] << 24 & 0xff000000));
                idx += 4;
            }
            if ((metaFlags & ISO18000p6C_META_BIT_MASK_RSSI) > 0)
            {
                if ((datlen - idx) < 1)
                {
                    //error data size
                    return;
                }
                rssi = tagData[idx];
                idx += 1;
            }
            if ((metaFlags & ISO18000P6C_META_BIT_MASK_READCOUNT) > 0)
            {
                if ((datlen - idx) < 1)
                {
                    //error data size
                    return;
                }
                readCnt = tagData[idx];
                idx += 1;
            }
            if ((metaFlags & ISO18000P6C_META_BIT_MASK_TAGDATA) > 0)
            {
                int r_len = datlen-idx;
                memcpy(readData,tagData+idx,r_len);
                CHAR c_rdata[r_len*2+1];
                memset(c_rdata,0,sizeof(c_rdata));
                BytesToHexStr(readData,r_len,c_rdata);
                s_rdata=QString(c_rdata);
            }


            for( i=0;i< m_tags_uhf.size();i++)
            {
                if(m_tags_uhf.at(i).m_uid == s_epc && m_tags_uhf.at(i).m_antNo == antID)
                {
                    break;
                }
            }
            //not exist
            if(i>=m_tags_uhf.size())
            {
                CTag_UHF newtag;
                newtag.m_counter = readCnt;
                newtag.m_uid =s_epc;//epc
                newtag.m_type = tagType;
                newtag.m_antNo =antID;
                newtag.m_AIP =AIPType;
                newtag.m_rssi=rssi;
                newtag.m_rdata = s_rdata;
                newtag.m_timestamp = timestamp;
                newtag.m_frequency = frequency;
                newtag.m_writeOper=QString("%1").arg(writeOper.data());
                newtag.m_lockOper=QString("%1").arg(lockOper.data());

                m_tags_uhf.push_back(newtag);
            }
            else
            {
                m_tags_uhf.at(i).m_counter++;
                if(m_tags_uhf.at(i).m_counter>=500000)
                {
                    m_tags_uhf.at(i).m_counter = 1;
                }
            }

            bool found = false;

        }

int CAEDevice_UHF::func_Inventory()
{
    err_t iret;
    if(this->ant_count<=0)
        return -ERR_ARG;
    BYTE newAI= AI_TYPE_NEW;

    //RDR_DisableAsyncTagReportOutput(hRdr);// disable async tag report output

    RFID_DN_HANDLE dnInvenParamList= RFID_HANDLE_NULL;
    dnInvenParamList = RDR_CreateInvenParamSpecList();
    if(dnInvenParamList)
    {
        /* set timeout */
        RDR_SetInvenStopTrigger(dnInvenParamList, INVEN_STOP_TRIGGER_TYPE_TIMEOUT, invenParams->m_timeout, 0);
        /* create ISO18000p6C air protocol inventory parameters */
        RFID_DN_HANDLE  AIPIso18000p6c = ISO18000p6C_CreateInvenParam(dnInvenParamList, 0, 0, ISO18000p6C_S0, ISO18000p6C_TARGET_A, ISO18000p6C_Dynamic_Q);
        if(AIPIso18000p6c) {
            //set selection parameters
            if (invenParams->m_sel->m_enable)
            {
                int bit_len=invenParams->m_sel->m_maskbits_len;
                int bytes_len=bit_len/8 + (bit_len%8==0?0:1);
                BYTE maskBits[bytes_len];
                memcpy(maskBits,invenParams->m_sel->m_maskbits,bytes_len);
                ISO18000p6C_SetInvenSelectParam(AIPIso18000p6c, invenParams->m_sel->m_target, invenParams->m_sel->m_action, invenParams->m_sel->m_memBank, invenParams->m_sel->m_pointer, maskBits, invenParams->m_sel->m_maskbits_len, 0);
            }
            // set inventory read parameters
            if(invenParams->m_metaFlags->m_tagData) {
                ISO18000p6C_SetInvenReadParam(AIPIso18000p6c ,invenParams->m_read->m_memBank,invenParams->m_read->m_wordPtr,(BYTE)invenParams->m_read->m_wordCnt);
            }

            // Add Embedded commands
            if(invenParams->m_write->m_enable) {
                int bytes_len = invenParams->m_write->m_wordCnt*2;
                BYTE writeDatas[bytes_len];
                memcpy(writeDatas,invenParams->m_write->m_datas,bytes_len);

                ISO18000p6C_CreateTAWrite(AIPIso18000p6c,
                                          invenParams->m_write->m_memBank,
                                          invenParams->m_write->m_wordPtr,
                                          invenParams->m_write->m_wordCnt,
                                          writeDatas, bytes_len);
            }

            if (invenParams->m_lock->m_enable)
            {
                UINT16 mask ,action;
                mask = action = 0;
                if (invenParams->m_lock->m_userMemSelected)
                {
                    mask |= 0x03;
                    action |=(UINT16)( invenParams->m_lock->m_userMem);
                }
                if (invenParams->m_lock->m_TIDMemSelected)
                {
                    mask |= (0x03 << 2);
                    action |= (UINT16)(invenParams->m_lock->m_TIDMem << 2);
                }
                if (invenParams->m_lock->m_EPCMemSelected)
                {
                    mask |= (0x03 << 4);
                    action |= (UINT16)(invenParams->m_lock->m_EPCMem << 4);
                }
                if (invenParams->m_lock->m_accessPwdSelected)
                {
                    mask|=(0x03 << 6);
                    action |= (UINT16)(invenParams->m_lock->m_accessPwd << 6);
                }
                if (invenParams->m_lock->m_killPwdSelected)
                {
                    mask |= (0x03 << 8);
                    action |= (UINT16)(invenParams->m_lock->m_killPwd << 8);
                }

                ISO18000p6C_CreateTALock(AIPIso18000p6c,mask,action);
            }
            // set meta flags
            if (invenParams->m_metaFlags->m_enable)
            {
                UINT32 metaFlags=0;
                if (invenParams->m_metaFlags->m_EPC)
                {
                    metaFlags |= ISO18000p6C_META_BIT_MASK_EPC;
                }
                if (invenParams->m_metaFlags->m_timestamp)
                {
                    metaFlags |= ISO18000P6C_META_BIT_MASK_TIMESTAMP;
                }
                if(invenParams->m_metaFlags->m_frequency ) {
                    metaFlags |= ISO18000P6C_META_BIT_MASK_FREQUENCY;
                }
                if(invenParams->m_metaFlags->m_RSSI) {
                    metaFlags |= ISO18000p6C_META_BIT_MASK_RSSI;
                }
                if(invenParams->m_metaFlags->m_readCnt ) {
                    metaFlags |= ISO18000P6C_META_BIT_MASK_READCOUNT;
                }
                if(invenParams->m_metaFlags->m_tagData) {
                    metaFlags |= ISO18000P6C_META_BIT_MASK_TAGDATA;
                }
                ISO18000p6C_SetInvenMetaDataFlags(AIPIso18000p6c ,metaFlags);
            }
            // set access password
            if (invenParams->m_metaFlags->m_tagData || invenParams->m_write->m_enable || invenParams->m_lock->m_enable)
            {
                ISO18000p6C_SetInvenAccessPassword(AIPIso18000p6c ,invenParams->m_accessPwd);
            }
        }
    }
    else
        return -ERR_MEM;

   DWORD nTagCount = 0;

    iret = RDR_TagInventory(hRdr,newAI,this->ant_count,this->antennas,dnInvenParamList);
    if (iret == 0 || iret == -ERR_STOPTRRIGOCUR)
    {
        nTagCount = RDR_GetTagDataReportCount(hRdr);
        RFID_TAG_HANDLE TagDataReport = RDR_GetTagDataReport(hRdr, RFID_SEEK_FIRST); //first
        while (TagDataReport)
        {
            UINT32 aip_id = 0;
            UINT32 tag_id = 0;
            UINT32 ant_id = 0;
            BYTE tagData[256];
            UINT32 nSize =sizeof(tagData);
            UINT32 metaFlags = 0;

            iret = ISO18000p6C_ParseTagReport(TagDataReport, &aip_id, &tag_id, &ant_id, &metaFlags, tagData, &nSize);
            if (iret == 0)
            {
                string writeOper = "";
                string lockOper = "";
                if (invenParams->m_write->m_enable)
                {
                    iret = ISO18000p6C_CheckTAWriteResult(TagDataReport);
                    if (iret != 0)
                    {
                        writeOper = "fail";
                    }
                    else
                    {
                        writeOper = "success";
                    }
                }
                if(invenParams->m_lock->m_enable)
                {
                    iret = ISO18000p6C_CheckTALockResult(TagDataReport);
                    if (iret != 0)
                    {
                        lockOper = "fail";
                    }
                    else
                    {
                        lockOper = "success";
                    }
                }
                AddNewISO18000P6CTag(aip_id, tag_id, ant_id, metaFlags, tagData, nSize, writeOper, lockOper);

            }

            TagDataReport = RDR_GetTagDataReport(hRdr, RFID_SEEK_NEXT); //next
        }
        if (iret == -ERR_STOPTRRIGOCUR) // stop trigger occur,need to inventory left tags
            iret = NO_ERR;

    }
    if (dnInvenParamList)
        DNODE_Destroy(dnInvenParamList);
    return iret;
}


err_t CAEDevice_UHF::AccessTag_Connect(CTag &tag,RFID_TAG_HANDLE *ht,DWORD accessPwd)
{
    CTag_UHF *pTag=(CTag_UHF *)&tag;
    const int ulen=pTag->m_uid.length()>2?pTag->m_uid.length()/2:0;
    BYTE byts[ulen];
    memset(byts,0,ulen);
    int blen=0;
    HexStrToBytes(pTag->m_uid.toStdString().c_str(),byts,blen);
    DWORD type=pTag->m_type;
//    BYTE addr_mode=0x01;//EPC - ISO18000p6C_ConnectV2
    int iret=0;

    iret=RDR_SetAcessAntenna(hRdr,(BYTE)(pTag->m_antNo<1?1:pTag->m_antNo));
    if(iret!=NO_ERR)
        return iret;
    iret=ISO18000p6C_Connect(hRdr,type,byts, blen,accessPwd,ht);
    return iret;
}

inline err_t CAEDevice_UHF::AccessTag_Disconnect(RFID_TAG_HANDLE ht)
{
    if(ht == NULL) return NO_ERR;
    int iret=RDR_TagDisconnect(hRdr,ht);
    if(iret!= NO_ERR)
        return iret;
}
err_t CAEDevice_UHF::func_AccessTag_UHF_Kill_Tag(CTag &tag, DWORD accessPwd, DWORD killPwd, BYTE rfu)
{
    CTag_UHF *m_tag=(CTag_UHF *)&tag;

    int iret = RDR_SetAcessAntenna(hRdr, m_tag->m_antNo);
    if (iret != 0)
    {
        return iret;
    }
    RFID_TAG_HANDLE ht;
    iret = AccessTag_Connect(tag, &ht, accessPwd);
    if (iret != 0)
    {
        return iret;
    }
    iret = ISO18000p6C_Kill(hRdr, ht, killPwd, rfu);
    if (iret != 0)
    {
        return iret;
    }
    iret = AccessTag_Disconnect(ht);
    return iret;
}
err_t CAEDevice_UHF::func_AccessTag_WriteData(CTag &tag, DWORD accessPwd,BYTE mem_type, DWORD mem_addr_word, DWORD mem_num_word, BYTE *data, DWORD dlen)
{
    CTag_UHF *m_tag=(CTag_UHF *)&tag;

    int iret = RDR_SetAcessAntenna(hRdr, m_tag->m_antNo);
    if (iret != 0)
    {
        return iret;
    }
    RFID_TAG_HANDLE ht;
    iret = AccessTag_Connect(tag, &ht, accessPwd);
    if (iret != 0)
    {
        return iret;
    }
    iret = ISO18000p6C_Write(hRdr, ht, mem_type, mem_addr_word, mem_num_word, data, dlen);
    if (iret != 0)
    {
        return iret;
    }
    iret = AccessTag_Disconnect(ht);
    return iret;
}
err_t CAEDevice_UHF::func_AccessTag_ReadData(CTag &tag, DWORD accessPwd,BYTE mem_type, DWORD mem_addr_word, DWORD mem_num_word, BYTE *data, DWORD &dlen)
{
    CTag_UHF *m_tag=(CTag_UHF *)&tag;

    int iret = RDR_SetAcessAntenna(hRdr, m_tag->m_antNo);
    if (iret != 0)
    {
        return iret;
    }
    RFID_TAG_HANDLE ht;
    iret = AccessTag_Connect(tag, &ht, accessPwd);
    if (iret != 0)
    {
        return iret;
    }
    iret = ISO18000p6C_Read(hRdr, ht, mem_type, mem_addr_word, mem_num_word, data, &dlen);
    if (iret != 0)
    {
        return iret;
    }
    iret = AccessTag_Disconnect(ht);
    return iret;
}

